# -*- coding: utf-8 -*-
import VBAPI
from win32com import client
import traceback
from enum import Enum


class modeltype(Enum):
    # from enum EpfcModelType
    asm = 'EpfcMDL_ASSEMBLY '
    prt = 'EpfcMDL_PART '
    drw = 'EpfcMDL_DRAWING '
    sec = 'EpfcMDL_2D_SECTION '
    lay = 'EpfcMDL_LAYOUT '
    dwg = 'EpfcMDL_DWG_FORMAT '
    mfg = 'EpfcMDL_MFG '
    rep = 'EpfcMDL_REPORT '
    mar = 'EpfcMDL_MARKUP '
    dia = 'EpfcMDL_DIAGRAM '
    nil = 'EpfcModelType_nil '


class macro(Enum):
    white_background = 'mapkey wb @MAPKEY_LABEL系统颜色-白底黑色;\
                      ~ Command `ProCmdRibbonOptionsDlg` ;\
                      ~ Select `ribbon_options_dialog` `PageSwitcherPageList` 1 `colors_layouts`;\
                      ~ Open `ribbon_options_dialog` `colors_layouts.Color_scheme_optMenu`;\
                      ~ Close `ribbon_options_dialog` `colors_layouts.Color_scheme_optMenu`;\
                      ~ Select `ribbon_options_dialog` `colors_layouts.Color_scheme_optMenu` 1 `2`;\
                      ~ Activate `ribbon_options_dialog` `OkPshBtn`;options_dialog` `OkPshBtn`;'
    default_background = 'mapkey wn @MAPKEY_LABEL自定义背景; ~ Select `main_dlg_cur` `appl_casc`;\
                        ~ Close `main_dlg_cur` `appl_casc`; ~ Command `ProCmdRibbonOptionsDlg` ;\
                        ~ Select `ribbon_options_dialog` `PageSwitcherPageList` 1 `colors_layouts`;\
                        ~ Open `ribbon_options_dialog` `colors_layouts.Color_scheme_optMenu`;\
                        ~ Close `ribbon_options_dialog` `colors_layouts.Color_scheme_optMenu`;\
                        ~ Select `ribbon_options_dialog` `colors_layouts.Color_scheme_optMenu` 1 \
                        `Custom`; ~ Activate `ribbon_options_dialog` `OkPshBtn`;'
    clear_appearance = 'mapkey `0 @MAPKEY_LABEL清除所有外观;\
                       ~ Activate `main_dlg_cur` `page_View_control_btn` 1;\
                       ~ Select `main_dlg_cur` `View:ProCmdViewGallery`;\
                       ~ Select `main_dlg_cur` \
                       `ProCmdViewGallery_layoutph.palette_holder.clearAppearance`;\
                       ~ Close `main_dlg_cur` \
                       `ProCmdViewGallery_layoutph.palette_holder.clearAppearance`;\
                       ~ Activate `main_dlg_cur` `clearAllAppearance`;\
                       ~ FocusIn `UI Message Dialog` `yes`;~ Activate `UI Message Dialog` `yes`;\
                       ~ Activate `main_dlg_cur` `page_Model_control_btn` 1;'
    view_refit = 'mapkey ee @MAPKEY_LABEL居中显示; ~ Command `ProCmdViewRefit`;'


class IAsyncConnection(object):

    def __init__(self):
        self.cAC = client.Dispatch(VBAPI.CCpfcAsyncConnection)  # 异步连接对象
        self.CREO_APP = 'C:/Program Files/PTC/Creo 6.0.4.0/Parametric/bin/parametric.exe'  # 程序目录
        # 程序启动选项
        # -g:no_graphics --Turn off the graphics display
        # -r:rpc_input   --Causes Creo Parametric to expect input from your asynchronous application only
        self.cmdline = self.CREO_APP + ' -g:no_graphics -i:rpc_input'
        # 初始连接为空
        self.AsyncConnection = None
        # 初始会话为空
        self.session = None

    def connect(self, Display=None, UserID=None, TextPath=None, TimeoutSec=None):
        # 连接现有会话

        self.AsyncConnection = self.cAC.Connect(Display, UserID, TextPath, TimeoutSec)
        self.session = self.get_session()
        return self.AsyncConnection

    def start(self, CmdLine=None, TextPath=''):
        if not CmdLine:
            self.AsyncConnection = self.cAC.Start(self.cmdline, TextPath)
        else:
            self.AsyncConnection = self.cAC.Start(CmdLine, TextPath)
        self.session = self.get_session()
        return self.AsyncConnection

    def end(self):
        if self.AsyncConnection:
            self.AsyncConnection.End()

    def disconnect(self, TimeoutSec=None):
        # 断开连接，保留进程
        if self.AsyncConnection:
            self.AsyncConnection.Disconnect(TimeoutSec)

    def isrunning(self):
        if self.AsyncConnection:
            return self.AsyncConnection.IsRunning

    def get_session(self):
        if self.AsyncConnection:
            return self.AsyncConnection.Session


class Isession(object):
    def __init__(self, session):
        self.session = session
        self.DIR = 'E:/python/test_data-3/'
        self.window = session.CurrentWindow
        self.model = session.CurrentModel
        self.id = session.ConnectionId

    def get_model(self, **kwargs):
        # 从工作区中获取模型
        if not kwargs:
            return self.session.GetActiveModel()
        if 'name' in kwargs.keys() and 'Type' in kwargs.keys():
            mtype = getattr(VBAPI.constants, modeltype(kwargs['Type']).value)
            return self.session.GetModel(kwargs['Name'], mtype)
        if 'mdldescr' in kwargs.keys():
            return self.session.GetModelFromDescr(kwargs['MdlDescr'])
        if 'filename' in kwargs.keys():
            return self.session.GetModelFromFileName(kwargs['FileName'])

    def retrieve_model(self, filename, path=None, askuseraboutreps=False):
        # 检索模型
        ModelDescriptor = client.Dispatch(VBAPI.CCpfcModelDescriptor)
        mdlDescr = ModelDescriptor.CreateFromFileName(filename)
        if not path:
            mdlDescr.Path = self.session.GetCurrentDirectory()
        else:
            mdlDescr.Path = path
        RetriveModelOptions = client.Dispatch(VBAPI.CCpfcRetrieveModelOptions)
        options = RetriveModelOptions.Create()
        if askuseraboutreps:
            options.AskUserAboutReps = True
        else:
            options.AskUserAboutReps = False

        return self.session.RetrieveModelWithOpts(mdlDescr, options)

    def set_directory(self, Path=None):
        if self.session:
            if not Path:
                self.session.ChangeDirectory(self.DIR)
            else:
                self.session.ChangeDirectory(Path)

    def get_modelwindow(self, model):
        return self.session.GetModelWindow(model)

    def create_modelwindow(self, model):
        return self.session.CreateModelWindow(model)

    def list_models(self):
        # retrieves the list of objects in the session
        return self.session.ListModels()

    def runmacro(self, macro):
        self.session.RunMacro(macro)


class Iwindow(object):
    def __init__(self, window):
        self.window = window
        self.id = window.GetId()

    def export_jpeg(self, filename):
        width = self.window.GraphicsAreaWidth * 10
        height = self.window.GraphicsAreaHeight * 10
        instructions = client.Dispatch(VBAPI.CCpfcJPEGImageExportInstructions).Create(height, width)
        image = self.window.ExportRasterImage(filename, instructions)
        return image

    def activate(self):
        self.window.Activate()

    def clear(self):
        self.window.Clear()

    def close(self):
        self.window.Close()


class Imodel(object):
    def __init__(self, model):
        self.model = model
        self.filename = model.FileName
        self.instancname = model.InstanceName
        self.extension = self.get_extension()
        self.material = self.get_material()


    def display(self):
        self.model.Display()

    def get_extension(self):
        return self.model.Descr.GetExtension()

    def export(self, filename=None, exportdata=None):
        if filename is None:
            filename = self.instancname + '.stp'
        if exportdata is None:
            exportdata = Exportdata()
            exportdata.set_flags()
        self.model.Export(filename, exportdata.instruction)

    # def set_exportdata(self, **kwargs):
    #     flags = client.Dispatch(VBAPI.CCpfcGeometryFlags).Create()
    #     if 'assolids' in kwargs.keys():
    #         flags.AsSolids = kwargs['assolids']
    #     else:
    #         flags.AsSolids = True
    #     if 'config' in kwargs.keys():
    #         config = getattr(VBAPI.constants, kwargs['config'])
    #     else:
    #         config = getattr(VBAPI.constants, 'EpfcEXPORT_ASM_SINGLE_FILE')
    #     instruction = client.Dispatch(VBAPI.CCpfcSTEP3DExportInstructions).Create(config, flags)
    #     return instruction

    def get_outline(self):
        outline3D = self.model.GeomOutline
        point1 = outline3D.Item(0)
        point2 = outline3D.Item(1)
        dx = abs(point1.Item(0) - point2.Item(0))
        dy = abs(point1.Item(1) - point2.Item(1))
        dz = abs(point1.Item(2) - point2.Item(2))
        outline = [dx, dy, dz]
        return outline

    def get_volume(self):
        massproperty = self.model.GetMassProperty(None)
        return massproperty.Volume

    def get_material(self):
        try:
            material = self.model.CurrentMaterial
            return material.Name
        except Exception:
            return None

    def get_param(self, name):
        return self.model.GetParam(name)

    def list_params(self):
        return self.model.ListParams()

class Exportdata(object):
    def __init__(self):
        self.flags = client.Dispatch(VBAPI.CCpfcGeometryFlags).Create()
        self.config = getattr(VBAPI.constants, 'EpfcEXPORT_ASM_SINGLE_FILE')
        self.instruction = client.Dispatch(VBAPI.CCpfcSTEP3DExportInstructions).Create(self.config, self.flags)

    def set_flags(self, kwargs={}):
        if 'assolids' in kwargs.keys():
            self.flags.AsSolids = kwargs['assolids']
        else:
            self.flags.AsSolids = True
        if 'assurfaces' in kwargs.keys():
            self.flags.AsSurfaces = kwargs['assurfaces']
        else:
            self.flagsAsSurfaces = False
        if 'config' in kwargs.keys():
            self.config = getattr(VBAPI.constants, kwargs['config'])
        else:
            self.config = getattr(VBAPI.constants, 'EpfcEXPORT_ASM_SINGLE_FILE')


if __name__ == '__main__':
    cont = IAsyncConnection()
    cont.connect()
    try:
        session = Isession(cont.session)
        session.set_directory()
        for model in session.list_models():
            model = Imodel(model)
            model.display()
            window = Iwindow(session.get_modelwindow(model.model))
            if model.extension == 'prt':
                window.activate()
                session.runmacro(macro.clear_appearance.value)

    except Exception as e:
        print(traceback.print_exc())
    finally:
        cont.disconnect()
